package com.zwan.oam_rtc.utils.messages;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

import lombok.extern.slf4j.Slf4j;

/**
 * WinntTCP 消息头
 * senderPID
 * receiverPID
 * eventid
 * len
 * type
 * secretfield
 * reverse[]
 * @author 叶建生
 * 
 */
@Slf4j
public class MessageHead extends AbstractStruct {
    private final static int SECRET_MASK = 0x956654AD;
    public final static ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN;

    private PID sender = new PID();
    private PID receiver = new PID();
    private int eventid;
    private int len = 0;
    private byte type = 0;
    private int secretfield = 0;
    private byte[] reverse = new byte[10];

    // private int reverse1 = 0;
    // private int reverse2 = 0;
    // private short reverse3 = 0;

    public MessageHead() {
        Arrays.fill(reverse, (byte) 0);
    }

    public int getEventid() {
        return eventid;
    }

    public void setEventid(int eventid) {
        this.eventid = eventid;
    }

    public int getBodyLen() {
        return len;
    }

    public void setBodyLen(int len) {
        this.len = len;
    }

    public PID getReceiver() {
        return receiver;
    }

    public void setReceiver(PID receiver) {
        this.receiver = receiver;
    }

    public int getSecretfield() {
        return secretfield;
    }

    public void setSecretfield(int secretfield) {
        this.secretfield = secretfield;
    }

    public PID getSender() {
        return sender;
    }

    public int getDestPno() {
        return receiver.getPno();
    }

    public void setDestPno(int destPno) {
        this.receiver.setPno(destPno);
    }

    public void setSender(PID sender) {
        this.sender = sender;
    }

    public byte getType() {
        return type;
    }

    public void setType(byte type) {
        this.type = type;
    }

    public int getLength() {
        return Const.MSG_HEAD_LEN;
    }
    
    /**
     * 从Buffer中读出messageHead（消息头），buffer中用0隔开senderPID和receivePID?
     */
    public void readFromBuffer(ByteBuffer bf) {
        bf.order(byteOrder);
        bf.get();  //zwan flag
        sender.readFromBuffer(bf);
        bf.get(); //zwan flag
        receiver.readFromBuffer(bf);
        eventid = bf.getShort();
        if (eventid < 0)
            eventid += 65536;
        len = bf.getShort();
        // if (len < 0) len += 65536;
        type = bf.get();
        secretfield = bf.getInt();
        bf.get(reverse);
    }
    /**
     * messageHead（消息头）写入Buffer，buffer中用0隔开senderPID和receivePID?
     */
    public void writeToBuffer(ByteBuffer bf) {
        bf.order(byteOrder);
        byte b = (byte)0;
        bf.put(b);
        sender.writeToBuffer(bf);
        bf.put(b);
        receiver.writeToBuffer(bf);
        bf.putShort((short) eventid);
        bf.putShort((short) len);
        bf.put(type);
        secretfield = encrypt(len, eventid, sender.getPno(), receiver.getPno());
        bf.putInt(secretfield);
        bf.put(reverse);
    }
    /**
     * messageHead（消息头）是否合法
     */
    public boolean isValid() {
        if (sender.getModule() == 0 && receiver.getModule() == 0)
            return true;
        return secretfield == calcSecretField() && (short) len <= Const.MAX_MSG_LEN;
    }
    
    /**
     * messageHead（消息头）中type是为-1 则为测试数据
     */
    public boolean isCheckMessage() {
        return type == Const.TCP_CHECK_TYPE;
    }
    
    /**
     * messageHead（消息头）中计算机密区域
     */
    public int calcSecretField() {
        return encrypt(len, eventid, sender.getPno(), receiver.getPno());
    }

    public static int encrypt(int len1, int event1, int spno1, int rpno1) {
        int nTemp1, nTemp2;
        short len = (short) len1;
        short event = (short) event1;
        short Spno = (short) spno1;
        short Rpno = (short) rpno1;
        if ((len & 0x0002) == 0) {
            nTemp1 = makeLong(len, event);
            nTemp1 &= SECRET_MASK;
            nTemp2 = makeLong(Rpno, Spno);
            nTemp2 = ~nTemp2;
            nTemp2 &= (~SECRET_MASK);
            nTemp1 |= nTemp2;
        } else {
            nTemp1 = makeLong(event, len);
            nTemp1 = ~nTemp1;
            nTemp1 &= SECRET_MASK;
            nTemp2 = makeLong(Spno, Rpno);
            nTemp2 &= (~SECRET_MASK);
            nTemp1 |= nTemp2;
        }

        return nTemp1;
    }

    private static int makeLong(short a, short b) {
        int temp;
        temp = (a & Const.BYTE16) | (b << 16);
        return temp;
    }
    
    /**
     * checkMessage
     * 将fromModlue写入MessageHead.sender中module，toModule写入MessageHead.reciver中的module
     * 设置MessageHead的各项参数，返回MessageHead的byteBuffer
     */
    public static byte[] getCheckMessage(byte fromModule, byte toModule) {
        return getCheckMessageBuff(fromModule, toModule).array();
    }

    public static ByteBuffer getCheckMessageBuff(short fromModule, short toModule) {
        byte[] checkBody = new byte[Const.TCP_CHECK_BODYLEN];
        Arrays.fill(checkBody, (byte) 0);
        ByteBuffer bf = ByteBuffer.allocate(Const.MSG_HEAD_LEN + checkBody.length);
        bf.order(byteOrder);
        bf.rewind();
        MessageHead head = new MessageHead();
        head.setType(Const.TCP_CHECK_TYPE);
        head.setEventid(0);
        head.setBodyLen(checkBody.length);
        head.getSender().setModule(fromModule);
        head.getReceiver().setModule(toModule);
        head.writeToBuffer(bf);
        bf.put(checkBody);
        return bf;
    }

    /**
     * messageHead（消息头）中交换senderPID和recivePID
     */
    public MessageHead swapPID() {
        MessageHead newHead = null;
        try {
            newHead = (MessageHead) this.clone();
            newHead.receiver = this.sender;
            newHead.sender = this.receiver;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return newHead;
    }
}
